
package com.scs.application.modules.base.service.impl;

import cn.afterturn.easypoi.excel.entity.ImportParams;
import cn.afterturn.easypoi.excel.entity.result.ExcelImportResult;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.google.common.collect.Lists;
import com.scs.application.consts.RoleConsts;
import com.scs.application.consts.SerialRuleConsts;
import com.scs.application.core.exceptions.BusinessException;
import com.scs.application.core.model.ImportResult;
import com.scs.application.core.serial.SerialUtils;
import com.scs.application.core.service.BaseServiceImpl;
import com.scs.application.core.thread.BatchSaveTask;
import com.scs.application.core.thread.DefaultSaveHandler;
import com.scs.application.core.utils.*;
import com.scs.application.modules.base.dto.ExcelSupplierDTO;
import com.scs.application.modules.base.entity.Material;
import com.scs.application.modules.base.entity.Supplier;
import com.scs.application.modules.base.mapper.SupplierMapper;
import com.scs.application.modules.base.request.SupplierQueryRequest;
import com.scs.application.modules.base.service.MaterialService;
import com.scs.application.modules.base.service.SupplierService;
import com.scs.application.modules.upms.entity.Office;
import com.scs.application.modules.upms.entity.User;
import com.scs.application.modules.upms.service.OfficeService;
import com.scs.application.modules.upms.service.UserService;
import com.scs.application.modules.upms.vo.UserVO;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import java.io.Serializable;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.stream.Collectors;


/**
 * 供应商 service 实现
 *
 */
@AllArgsConstructor
@Slf4j
@Service
public class SupplierServiceImpl extends BaseServiceImpl<SupplierMapper, Supplier> implements SupplierService {

    private SupplierMapper supplierMapper;

    private final OfficeService officeService;

    private final UserService userService;

    @Override
    public Supplier findByOfficeId(String officeId) {
        return this.getOne(Wrappers.<Supplier>query().eq("office_id", officeId));
    }

    @Override
    public void addSupplier(Supplier entity) {
        entity.setCode(SerialUtils.generateCode(SerialRuleConsts.BASE_SUPPLIER_CODE));
        if (StringUtils.isBlank(entity.getLoginKey())) {
            entity.setLoginKey(entity.getCode());
        }
        distributedSave(entity);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void changeLoginKey(String id, String newLoginKey) {
        Supplier supplier = this.getById(id);
        // 修改用户表
        userService.changeLoginKey(supplier.getLoginKey(), newLoginKey);
        // 修改供应商表
        this.update(Wrappers.<Supplier>update().eq("id", id)
                .set("login_key", newLoginKey)
        );
    }

    @Override
    public IPage<Supplier> page(SupplierQueryRequest request) {
        IPage page = this.page(request.getPage(), Wrappers.<Supplier>query()
                // .eq(UserUtils.getUser().isSupplier(), "id", UserUtils.getSupplierId())
                .like(StringUtils.isNotBlank(request.getCompanyCode()), "company_code", request.getCompanyCode())
                .like(StringUtils.isNotBlank(request.getName()), "name", request.getName())
                .like(StringUtils.isNotBlank(request.getLoginKey()), "login_key", request.getLoginKey())
                /*.eq(request.getIsDrug() != null, "is_drug", request.getIsDrug())
                .eq(request.getIsConsumable() != null, "is_consumable", request.getIsConsumable())
                .eq(request.getIsReagent() != null, "is_reagent", request.getIsReagent())*/
                .orderByDesc("gmt_modified")
        );
        return page;
    }


    @Override
    public List<Supplier> list(SupplierQueryRequest request) {
        List<Supplier> list = this.list(Wrappers.<Supplier>query()
                .orderByDesc("gmt_modified")
        );
        return list;
    }

    @Override
    public IPage<Supplier> pageByKeywords(SupplierQueryRequest request, String keywords) {
        IPage page = this.page(request.getPage(), Wrappers.<Supplier>query()
                .like(StringUtils.isNotBlank(keywords), "company_code", keywords)
                .or()
                .like(StringUtils.isNotBlank(keywords), "code", keywords)
                .or()
                .like(StringUtils.isNotBlank(keywords), "name", keywords)
                .orderByDesc("gmt_modified")
        );
        return page;
    }

    /**
     * 查询当前医院下不存在供应商
     */
    @Override
    public IPage<Supplier> pageHospitalNotExisted(SupplierQueryRequest request) {
        request.setHospitalId(UserUtils.getHospitalId());
        return supplierMapper.pageHospitalNotExist(request.getPage(), request);
    }


    @Override
    public ImportResult excelImport(MultipartFile file) {
        return excelImport(file, null);
    }

    /**
     * 供应商导入
     */
    @Override
    public ImportResult excelImport(MultipartFile file, Map<String, Object> params) {
        return super.excelImport(file, params);
    }

    //    @LcnTransaction
    @Override
    protected ExcelImportResult doExcelImport(MultipartFile multipartFile, Map<String, Object> params) throws Exception {
        ImportParams importParams = PoiUtils.getDefaultImportParams();
        long currentTimeMillis = System.currentTimeMillis();
        ExcelImportResult importResult = PoiUtils.importExcelMore(multipartFile.getInputStream(), ExcelSupplierDTO.class, importParams);
        log.info("文件加载耗时：{}", DateUtils.formatTime(System.currentTimeMillis() - currentTimeMillis));

        List<ExcelSupplierDTO> dtoList = Lists.newArrayList(importResult.getList());

        List<Supplier> existSupplier = list(Wrappers.<Supplier>query().select("id,name"));
        Map<String, Supplier> supplierMap = existSupplier.stream().collect(Collectors.toMap(o -> o.getName(), o -> o, (o1, o2) -> o1));
        log.info("加载到{}条供应商数据", supplierMap.size());

        ConcurrentLinkedQueue<Supplier> result = new ConcurrentLinkedQueue();

        DefaultSaveHandler<ExcelSupplierDTO> saveHandler = new DefaultSaveHandler<ExcelSupplierDTO>() {

            @Override
            public void doSave(int currentIndex, ExcelSupplierDTO entity) throws BusinessException {
                entity.setRegionId(0L); // default
                Supplier supplier = supplierMap.get(entity.getName());
                if (supplier != null) {
                    entity.setId(supplier.getId());
                    log.warn("第{}行供应商{}已存在，不进行操作，请注意", currentIndex, supplier.getName());
                    return;
                }


                Supplier newSupplier = new Supplier();
                BeanUtils.copyProperties(entity, newSupplier);

                if (StringUtils.isBlank(entity.getCode())) {
                    newSupplier.setCode(SerialUtils.generateCode(SerialRuleConsts.BASE_SUPPLIER_CODE));
                }
                if (StringUtils.isBlank(entity.getCompanyCode())) {
                    newSupplier.setCompanyCode(newSupplier.getCode());
                }

                String loginKey = StringUtils.defaultIfBlank(entity.getLoginKey(), newSupplier.getCode());
                String pinyin = PinYinUtils.getAlpha(entity.getName());
                newSupplier.setPinyin(StringUtils.substring(pinyin, 0, 10));
                newSupplier.setLoginKey(loginKey);
                try {
                    distributedSave(newSupplier);
                } catch (Exception e) {
                    importResult.getList().remove(entity);
                    importResult.getFailList().add(entity);
                    entity.setErrorMsg(e.getMessage());
                }
            }
        };
        BatchSaveTask<Supplier> task = new BatchSaveTask(saveHandler, dtoList);

        this.forkJoinPool.invoke(task);

        List<Supplier> updateSuppliers = result.stream().filter(o -> StringUtils.isNotBlank(o.getId())).collect(Collectors.toList());
        List<Supplier> insertSuppliers = result.stream().filter(o -> StringUtils.isBlank(o.getId())).collect(Collectors.toList());
        if (!updateSuppliers.isEmpty()) {
            this.updateBatchById(updateSuppliers);
        }
        if (!insertSuppliers.isEmpty()) {
            //this.saveBatch(insertSuppliers);
            this.baseMapper.insertBatchSomeColumn(Lists.newArrayList(insertSuppliers));
        }
        return importResult;
    }

    @Transactional
    public void distributedSave(Supplier supplier) {
        //判断供应商名称是否存在
        Supplier s = this.baseMapper.selectOne(Wrappers.<Supplier>query().eq("name", supplier.getName()));
        if (s != null) {
            throw new BusinessException("供应商名称" + supplier.getName() + "已存在");
        }
        //判断供应商code是否已经存在,如果存在重新生成code
        Supplier sp = this.baseMapper.selectOne(Wrappers.<Supplier>query().eq("code", supplier.getCode()));
        if (sp != null) {
            String code = SerialUtils.generateCode(SerialRuleConsts.BASE_SUPPLIER_CODE);
            String loginKey = StringUtils.defaultIfBlank(supplier.getLoginKey(), code);
            supplier.setCode(code).setLoginKey(loginKey);
        }
        // 当新增供应商时添加机构、用户
        Office office = new Office();
        office.setCode(supplier.getCompanyCode()).setType(Office.TYPE_SUPPLIER).setSort(1l)
                .setName(supplier.getName()).setParentId("0");
        if (!officeService.save(office)) {
            throw new BusinessException("机构添加失败");
        }
        supplier.setOfficeId(office.getId());

        UserVO userVO = new UserVO();
        userVO.setOfficeId(office.getId())
                .setLoginKey(supplier.getLoginKey())
                .setNickname(supplier.getName())
                .setEmail(supplier.getEmail())
                .setMobile(supplier.getMobile())
                .setRoleCodes(Lists.newArrayList(RoleConsts.SUPPLIER_MANAGER))
                .setRemark("供应商" + supplier.getName() + "主账号");

        User user = userService.addUser(userVO);
        if (user == null) {
            throw new BusinessException("主用户" + supplier.getLoginKey() + "可能已存在，添加失败");
        }
        this.save(supplier);
    }

    @Override
    public boolean removeCascadeBatchByIds(Collection<? extends Serializable> idList) {
        if (SpringUtils.getBean(MaterialService.class).count(Wrappers.<Material>query().in("supplier_id", idList)) > 0) {
            BusinessException.throwError("所选供应商已有相关商品，不允许删除");
        }
        return super.removeCascadeBatchByIds(idList);
    }
}
